package cn.coisini.utils;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import eu.bitwalker.useragentutils.UserAgent;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.log4j.Log4j2;
import org.lionsoul.ip2region.xdb.Searcher;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.*;
import java.util.Objects;

/**
 * @author xiangshaw
 * Description: 获取IP
 */
@Log4j2
public class IpUtils {

    private IpUtils() {
        throw new IllegalArgumentException("IpUtils class");
    }

    private static final String FORMAT_URL = "https://apis.map.qq.com/ws/location/v1/ip?ip={}&key=4TPBZ-BMT6G-6MTQX-QLTMP-NL2GK-DLB7U";
    private static final String LOCAL_IP = "127.0.0.1";
    private static final String RESOURCE_NAME = "ip2region.xdb";
    public static final String UNKNOWN = "unknown";


    private static Searcher searcher = null;

    static {
        // 从资源文件中加载 xdb 内容
        try {
            String path = Objects.requireNonNull(IpUtils.class.getClassLoader().getResource(RESOURCE_NAME)).getPath();
            byte[] bytes = Searcher.loadContentFromFile(path);
            searcher = Searcher.newWithBuffer(bytes);
        } catch (Exception e) {
            log.error("加载资源文件失败: {}", RESOURCE_NAME, e);
        }
    }

    /**
     * 获取客户端 IP 地址
     *
     * @param request HTTP 请求
     * @return 客户端 IP 地址
     */
    public static String getIp(HttpServletRequest request) {
        String ipAddress = extractIpAddress(request);
        if (LOCAL_IP.equals(ipAddress) || ipAddress == null) {
            ipAddress = getLocalIp();
        }
        return "0:0:0:0:0:0:0:1".equals(ipAddress) ? LOCAL_IP : ipAddress;
    }

    /**
     * 从请求头中提取 IP 地址
     *
     * @param request HTTP 请求
     * @return 提取的 IP 地址
     */
    private static String extractIpAddress(HttpServletRequest request) {
        String[] headers = {
                "x-forwarded-for",
                "Proxy-Client-IP",
                "WL-Proxy-Client-IP"
        };

        for (String header : headers) {
            String ip = request.getHeader(header);
            if (ip != null && !ip.isEmpty() && !UNKNOWN.equalsIgnoreCase(ip)) {
                return ip.split(",")[0].trim();
            }
        }
        return request.getRemoteAddr();
    }

    /**
     * 获取本地 IP 地址
     *
     * @return 本地 IP 地址
     */
    private static String getLocalIp() {
        try {
            InetAddress inet = InetAddress.getLocalHost();
            return inet.getHostAddress();
        } catch (UnknownHostException e) {
            log.error("获取本地 IP 失败：", e);
            return LOCAL_IP;
        }
    }

    /**
     * 根据 IP 地址获取城市信息
     *
     * @param ip IP 地址
     * @return 城市信息
     */
    public static String getCityInfo(String ip) {
        String response = analyzeIp(ip);
        return parseCityInfo(response);
    }

    /**
     * 解析城市信息
     *
     * @param jsonResponse IP 查询的 JSON 响应
     * @return 城市信息
     */
    private static String parseCityInfo(String jsonResponse) {
        String address = "";
        try {
            // 打印 JSON 响应用于调试
            log.debug("JSON 响应: {}", jsonResponse);

            // 使用 fastjson 解析 JSON
            JSONObject jsonObject = JSON.parseObject(jsonResponse);
            if (jsonObject.containsKey("status") && jsonObject.getInteger("status") == 0) {
                JSONObject result = jsonObject.getJSONObject("result");
                JSONObject addressInfo = result.getJSONObject("ad_info");
                String nation = addressInfo.getString("nation");
                String province = addressInfo.getString("province");
                String city = addressInfo.getString("city");
                address = String.format("%s-%s-%s", nation, province, city);
            }
        } catch (Exception e) {
            log.error("解析城市信息失败：", e);
        }
        return address;
    }

    /**
     * 使用 ip2region 解析 IP 地址
     *
     * @param ip IP 地址
     * @return IP 地址信息
     */
    public static String getIp2region(String ip) {
        if (searcher == null) {
            log.error("Error: DbSearcher is null");
            return null;
        }

        try {
            String ipInfo = searcher.search(ip);
            if (ipInfo != null) {
                ipInfo = ipInfo.replace("|0", "").replace("0|", "");
            }
            return ipInfo;
        } catch (Exception e) {
            log.error("获取 IP 地址信息失败：", e);
            return null;
        }
    }

    /**
     * 获取访问设备的用户代理
     *
     * @param request HTTP 请求
     * @return 用户代理
     */
    public static UserAgent getUserAgent(HttpServletRequest request) {
        return UserAgent.parseUserAgentString(request.getHeader("User-Agent"));
    }

    /**
     * 获取本地 IP 地址
     *
     * @return 本地 IP 地址
     */
    public static String getHostIp() {
        try {
            return InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException e) {
            log.error("获取本地 IP 地址失败：", e);
            return LOCAL_IP;
        }
    }

    /**
     * 获取本地主机名
     *
     * @return 本地主机名
     */
    public static String getHostName() {
        try {
            return InetAddress.getLocalHost().getHostName();
        } catch (UnknownHostException e) {
            log.error("获取主机名失败：", e);
            return "未知";
        }
    }

    /**
     * 根据在腾讯位置服务上申请的 key 进行请求解析 IP
     *
     * @param ip IP 地址
     * @return IP 解析结果
     */
    public static String analyzeIp(String ip) {
        StringBuilder result = new StringBuilder();
        try (BufferedReader in = new BufferedReader(new InputStreamReader(getUrl(ip).openStream()))) {
            String line;
            while ((line = in.readLine()) != null) {
                result.append(line);
            }
        } catch (Exception e) {
            log.error("发送 GET 请求出现异常：", e);
            //继续执行后面的代码
            return "";
        }
        return result.toString();
    }

    /**
     * 获取 URL 对象
     *
     * @param ip IP 地址
     * @return URL 对象
     * @throws URISyntaxException、MalformedURLException 异常
     */
    private static URL getUrl(String ip) throws URISyntaxException, MalformedURLException {
        String urlString = FORMAT_URL.replace("{}", ip);
        URI uri = new URI(urlString);
        return uri.toURL();
    }
}

